package us.mooresr.webtroopmanager.client;

import java.util.HashSet;
import java.util.Set;

import us.mooresr.webtroopmanager.client.events.PermissionChangedEvent;
import us.mooresr.webtroopmanager.shared.Privilege;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;


public class SecurityManager {
	private Long userId=null;
	private Set<Privilege> privileges = new HashSet<Privilege>();
	private Set<Long> people = new HashSet<Long>();
	private Set<Long> myVehicles = new HashSet<Long>();
	private SimpleEventBus eventBus;
	
	public SecurityManager(EventBus eventBus) {
		this.eventBus = (SimpleEventBus) eventBus;
		
	}
	
	
	public void setUserId(Long userId) {
		this.userId = userId;
		
		// Fill in privileges based on the userId
		TroopManagerServiceAsync troopManagerService = (TroopManagerServiceAsync) GWT.create(TroopManagerService.class);

		AsyncCallback<Set<Privilege>> callback = new AsyncCallback<Set<Privilege>>() {

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("getUserPrivileges failed");
			
				privileges = null;
			}

			@Override
			public void onSuccess(Set<Privilege> result) {
				privileges = result;
				eventBus.fireEvent(new PermissionChangedEvent(result));

			}

		};
		
		if (userId != null) {
			troopManagerService.getUserPrivileges(userId, callback);
		} else {
			if (privileges != null) {
				privileges.clear();
			}
		}
		
		
		// Get the people (Set of class Person) represented by this user
		AsyncCallback<Set<Long>> callback2 = new AsyncCallback<Set<Long>>() {

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("getMatchingPeople failed");
				people = null;
			}

			@Override
			public void onSuccess(Set<Long> result) {
					people = result;			
			}
			
		};
		
		if (userId != null) {
			troopManagerService.getMatchingPeople(userId, callback2);
		} else {
			if (people != null) {
				people.clear();
			}
		}
		
		// Get the set of vehicles this user owns
		AsyncCallback<Set<Long>> callback3 = new AsyncCallback<Set<Long>>() {

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("getUsersVehicles failed");
				myVehicles = null;
				
			}

			@Override
			public void onSuccess(Set<Long> result) {
				myVehicles = result;
				
			}
		};
		
		if (userId != null) {
			troopManagerService.getUsersVehicles(userId, callback3);
		} else {
			if (myVehicles != null) {
				myVehicles.clear();
			}
		}
	}
	
	public Long getUserId() {
		return userId;
	}
	
	public Boolean hasPrivilege(Privilege p) {
		if (privileges.contains(p)) {
			return true;
		} else {
			return false;
		}		
	}
	
	/**
	 * Given a Privilege that represents an action and an object to be acted on, return true iff the action is allowed.
	 * @param p - One of a limited set of Privilege values
	 * @param ObjectId - The Long ID of the object being acted on
	 * @return
	 */
	
	public Boolean isAllowed(Privilege p, Long ObjectId) {
		Boolean allowed = false;
		
		switch(p) {
		case ADD_PERSON:
			if (hasPrivilege(Privilege.ADD_PERSON)) {
				allowed = true;
			}
			break;
		case DELETE_PERSON:
			if (hasPrivilege(Privilege.DELETE_PERSON)) {
				allowed = true;
			}
			break;
		case MODIFY_PERSON:
			if (hasPrivilege(Privilege.MODIFY_PERSON)) {
				allowed = true;
			} else {
				if (hasPrivilege(Privilege.MODIFY_SELF) && isSelf(ObjectId)) {
					allowed = true;
				}
			}
			break;
		case ADD_EVENT:
			if (hasPrivilege(Privilege.ADD_EVENT)) {
				allowed = true;
			}
			break;
		case DELETE_EVENT:
			if (hasPrivilege(Privilege.DELETE_EVENT)) {
				allowed = true;
			}
			break;
		case ADD_PERSON_TO_EVENT:
			if (hasPrivilege(Privilege.ADD_PERSON_TO_EVENT)) {
				allowed = true;
			} else {
				if (hasPrivilege(Privilege.ADD_SELF_TO_EVENT) && isSelf(ObjectId)) {
					allowed = true;
				}
			}
			break;
		case REMOVE_PERSON_FROM_EVENT:
			if (hasPrivilege(Privilege.REMOVE_PERSON_FROM_EVENT)) {
				allowed = true;
			} else {
				if (hasPrivilege(Privilege.REMOVE_SELF_FROM_EVENT) && isSelf(ObjectId)) {
					allowed = true;
				}
			}
			break;
		case ADD_DRIVER_TO_EVENT:
			if (hasPrivilege(Privilege.ADD_DRIVER_TO_EVENT)) {
				allowed = true;
			} else {
				if (hasPrivilege(Privilege.ADD_SELF_TO_DRIVERS) && isSelf(ObjectId)) {
					allowed = true;
				}
			}
			break;
		case REMOVE_DRIVER_FROM_EVENT:
			if (hasPrivilege(Privilege.REMOVE_DRIVER_FROM_EVENT)) {
				allowed = true;
			} else {
				if (hasPrivilege(Privilege.REMOVE_SELF_FROM_DRIVERS) && isSelf(ObjectId)) {
					allowed = true;
				}
			}
			break;
		case ADD_VEHICLE:
			if (hasPrivilege(Privilege.ADD_VEHICLE)) {
				allowed = true;
			}
			break;
		case DELETE_VEHICLE:
			if (hasPrivilege(Privilege.DELETE_VEHICLE)) {
				allowed = true;
			} else {
				if (hasPrivilege(Privilege.DELETE_OWN_VEHICLE) && isMine(ObjectId)) {
					allowed = true;
				}
			}
			break;
		case MODIFY_VEHICLE:
			if (hasPrivilege(Privilege.MODIFY_VEHICLE)) {
				allowed = true;
			} else {
				if (hasPrivilege(Privilege.MODIFY_OWN_VEHICLE) && isMine(ObjectId)) {
					allowed = true;
				}
			}
			break;
		case MODIFY_EVENT:
			if (hasPrivilege(Privilege.MODIFY_EVENT)) {
				allowed = true;
			}
			break;
		default:
			// Ought to be some kind of error here
			break;
		}

		return allowed;
	}


	private boolean isSelf(Long personId) {
		if (people.contains(personId)) {
			return true;
		} else {
			return false;
		}		
	}
	
	private boolean isMine(Long vehicleId) {
		if (myVehicles.contains(vehicleId)) {
			return true;
		} else {
			return false;
		}
	}


}
